package preprocessing;

import gridmath.CaseMatrixBase;
import gridmath.ExpectedCasesCalculator;
import gridmath.ExpectedControlsCalculator;
import gridmath.FrequencyCalculator;
import gridmath.MatrixOperations;
import gridmath.MaxCaseCalculator;
import gridmath.NeededCaseCalculator;
import pac.SearchDatastructure;
import datastructures.UserParameters;

public class SimpleConstraintHandler {

	private final UserParameters userParams;
	private final WindowingSystem windowMaker;
	private final SearchDatastructure searcher;
	
	private final CaseMatrixBase pSignificantMatrix;

		
	/*
	 * Constructor initializes the interaction frequencies.
	 */
	public SimpleConstraintHandler ( SearchDatastructure I )
		throws Exception 
	{	
		searcher = I;
		userParams = searcher.userParams;
		windowMaker = searcher.windowMaker;
		
		//1. Make a frequency grid	
		System.out.println("Making frequency hypergrid ... ");	
		FrequencyCalculator frequencyGrid = new FrequencyCalculator ( userParams, windowMaker );
		frequencyGrid.compute ( MatrixOperations.calculateFrequency, new CaseMatrixBase(windowMaker, userParams.getMaxorder()),  true );
		
		
		//3. Calculate expected Cases and expected Controls given the expected Penetrance
		System.out.println("Calculating expected Controls and Cases for various allelic combinations ... ");	
	
		ExpectedCasesCalculator expectedCases = new ExpectedCasesCalculator ( userParams, windowMaker );
		expectedCases.compute (MatrixOperations.calculateExpectedCases, frequencyGrid,  true );
		ExpectedControlsCalculator expectedControls = new ExpectedControlsCalculator ( userParams, windowMaker );
		expectedControls.compute (MatrixOperations.calculateExpectedControls, frequencyGrid,  true );		
		
		//4. Calculate number of cases needed against expected Controls for significance, avoiding those requiring too many
		System.out.println("Calculating case carriers needed for significance ... ");
		
		NeededCaseCalculator neededCases = new NeededCaseCalculator ( userParams, windowMaker, searcher.significance );
		neededCases.compute ( MatrixOperations.calculateNeededCases, expectedCases, true );		
		CaseMatrixBase tooManyCasesForSignificance = new CaseMatrixBase( windowMaker, userParams.getMaxorder(), userParams.getNumber_of_cases()); 
		neededCases.compute(MatrixOperations.lessThan, tooManyCasesForSignificance, true);
		
		//5. Scan out coordinates where there are no SNP-combinations according to the data
//		System.out.println("Screening out coordinates with no SNP combinations ... ");
		
//		NonemptyCoordinatesCalculator nonemptyCoordinates = new NonemptyCoordinatesCalculator(userParams, windowMaker, searcher);
//		nonemptyCoordinates.compute(MatrixOperations.calculateNonZeroCoordinates, null, true);		
//		neededCases.compute(MatrixOperations.matrixMultiply, nonemptyCoordinates, true);
		
		//6. Screen out coordinates that will never make it
		System.out.println("Screening out SNPs whose maximal overlap will not make significance ... ");
		
		MaxCaseCalculator maxCases = new MaxCaseCalculator ( userParams, windowMaker );	
		maxCases.compute ( MatrixOperations.calculateMaxCases, frequencyGrid,  true );
		maxCases.compute(MatrixOperations.matrixMultiply, (new CaseMatrixBase(windowMaker, userParams.getMaxorder(), userParams.getNumber_of_cases())), true);
		
		neededCases.compute( MatrixOperations.lessThan, maxCases, true );
		neededCases.compute(MatrixOperations.greaterThan, (new CaseMatrixBase(windowMaker, userParams.getMaxorder(), 1)), true);
		
		//8. Calculate the probability matrix from the remaining coordinates.
		System.out.println("Calculating probability matrix assuming interactions at levels needed for significance ...");	
		
		double denominator = (double) 1 / (double) userParams.getNumber_of_cases();
		pSignificantMatrix = neededCases.compute( MatrixOperations.matrixMultiply, (new CaseMatrixBase(windowMaker, userParams.getMaxorder(), denominator)), false );
		
	}
	
	/*
	 * Significance Frequencies at Coordinates
	 */
	public CaseMatrixBase getPSignificantMatrix() {
		return pSignificantMatrix;
	}
	
	/*
	 * Lowest Expected Frequencies at Coordinates
	 */
	public CaseMatrixBase getPLEMatrix() {
		CaseMatrixBase pLEMatrix = new FrequencyCalculator ( userParams, windowMaker );
		pLEMatrix.compute ( MatrixOperations.calculateFrequency, new CaseMatrixBase(windowMaker, userParams.getMaxorder()),  true );
		return pLEMatrix;
	}
	
}
